﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace VirtualBank.Common.UserControls
{
    public enum ClickState
    {
        IDLE,
        WAITING_RELEASE,
        WAITING_DOUBLECLICK,
        WAITING_DOUBLECLICK_RELEASE,
        LONGPRESS_HOLDING
    }
    /// <summary>
    /// LongPressButtonEx.xaml 的交互逻辑
    /// </summary>
    public partial class LongPressButton : UserControl
    {
        public LongPressButton()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        private DispatcherTimer _pressDispatcherTimer;
        private DispatcherTimer _clickDispatcherTimer;
        private DispatcherTimer _senderDispatcherTimer;
        private ClickState _clickState = ClickState.IDLE;

        /// <summary>
        /// 长按事件
        /// </summary>
        public event RoutedEventHandler LongPress
        {
            add => AddHandler(LongPressEvent, value);
            remove => RemoveHandler(LongPressEvent, value);
        }
        public static readonly RoutedEvent LongPressEvent
             = EventManager.RegisterRoutedEvent("LongPress",
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(LongPressButton));


        /// <summary>
        /// 长按松开事件
        /// </summary>
        public event RoutedEventHandler LongPressRelease
        {
            add => AddHandler(LongPressReleaseEvent, value);
            remove => RemoveHandler(LongPressReleaseEvent, value);
        }
        public static readonly RoutedEvent LongPressReleaseEvent
            = EventManager.RegisterRoutedEvent("LongPressRelease",
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(LongPressButton));


        /// <summary>
        /// 单击事件
        /// </summary>
        public event RoutedEventHandler Click
        {
            add => AddHandler(ClickEvent, value);
            remove => RemoveHandler(ClickEvent, value);
        }
        public static readonly RoutedEvent ClickEvent
            = EventManager.RegisterRoutedEvent("Click",
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(LongPressButton));

        /// <summary>
        /// 双击事件
        /// </summary>
        public event RoutedEventHandler DoubleClick
        {
            add => AddHandler(DoubleClickEvent, value);
            remove => RemoveHandler(DoubleClickEvent, value);
        }
        public static readonly RoutedEvent DoubleClickEvent
            = EventManager.RegisterRoutedEvent("DoubleClick",
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(LongPressButton));


        /// <summary>
        /// 长按的判定时间
        /// </summary>
        public int LongPressTime
        {
            get { return (int)GetValue(LongPressTimeProperty); }
            set { SetValue(LongPressTimeProperty, value); }
        }
        public static readonly DependencyProperty LongPressTimeProperty
            = DependencyProperty.Register("LongPressTime",
                typeof(int),
                typeof(LongPressButton),
                new PropertyMetadata(300));

        /// <summary>
        /// 按键的文本
        /// </summary>
        public string ButtonContent
        {
            get { return (string)GetValue(BtnContentProperty); }
            set { SetValue(BtnContentProperty, value); }
        }
        public static readonly DependencyProperty BtnContentProperty
            = DependencyProperty.Register("ButtonContent",
                typeof(string),
                typeof(LongPressButton),
                new PropertyMetadata(""));

        /// <summary>
        /// 按键的可用性
        /// </summary>
        public bool ButtonIsEnable
        {
            get { return (bool)GetValue(ButtonIsEnableProperty); }
            set { SetValue(ButtonIsEnableProperty, value); }
        }
        public static readonly DependencyProperty ButtonIsEnableProperty =
            DependencyProperty.Register("ButtonIsEnable", typeof(bool), typeof(LongPressButton), new PropertyMetadata(true));





        /// <summary>
        /// 按键时长到后的处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PressDispatcherTimeOut(object sender, EventArgs e)
        {
            StateChange(0);
        }

        /// <summary>
        /// 双击判断时长到后的处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickDispatcherTimeOut(object sender, EventArgs e)
        {
            StateChange(0);
        }

        /// <summary>
        /// 长按持续期间的操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SenderDispatcherTimeOut(object sender, EventArgs e)
        {
            if (ClickState.LONGPRESS_HOLDING == _clickState)
            {
                RaiseEvent(new RoutedEventArgs(LongPressEvent,this));
            }
        }

        /// <summary>
        /// 按钮左键按下后
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            StateChange(1);
        }

        /// <summary>
        /// 按钮左键抬起后
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            StateChange(1);
        }

        /// <summary>
        /// 状态机处理函数
        /// </summary>
        /// <param name="sign">表示调用入口，0位计时器工作函数，1位控件动作</param>
        private void StateChange(int sign)
        {
            switch (_clickState)
            {
                case ClickState.IDLE:
                default:
                    if (sign == 1)
                    {
                        _clickState = ClickState.WAITING_RELEASE;
                        _clickDispatcherTimer.IsEnabled = true;
                        _pressDispatcherTimer.IsEnabled = true;
                    }                    
                    break;
                case ClickState.WAITING_RELEASE:
                    _pressDispatcherTimer.Stop();
                    if (0 == sign)
                    {
                        _pressDispatcherTimer.IsEnabled = false;
                        _clickState = ClickState.LONGPRESS_HOLDING;                        
                        _clickDispatcherTimer.IsEnabled = false;
                        _senderDispatcherTimer.IsEnabled = true;
                        RaiseEvent(new RoutedEventArgs(LongPressEvent,this));
                    }
                    else if (1 == sign)
                    {
                        _pressDispatcherTimer.IsEnabled = false;
                        _senderDispatcherTimer.IsEnabled = false;
                        _clickState = ClickState.WAITING_DOUBLECLICK;
                    }
                    break;
                case ClickState.WAITING_DOUBLECLICK:
                    _clickDispatcherTimer.IsEnabled = false;
                    _senderDispatcherTimer.IsEnabled = false;
                    _pressDispatcherTimer.IsEnabled = false;
                    if (0 == sign)
                    {
                        RaiseEvent(new RoutedEventArgs(ClickEvent,this));
                        _clickState = ClickState.IDLE;
                    }
                    else if (1 == sign)
                    {                        
                        _clickState = ClickState.WAITING_DOUBLECLICK_RELEASE;
                    }                    
                    break;
                case ClickState.WAITING_DOUBLECLICK_RELEASE:
                    _clickState = ClickState.IDLE;
                    RaiseEvent(new RoutedEventArgs(DoubleClickEvent,this)); 
                    break;
                case ClickState.LONGPRESS_HOLDING:
                    _senderDispatcherTimer.IsEnabled = false;
                    _clickState = ClickState.IDLE;   
                    _clickDispatcherTimer.IsEnabled = false;
                    _pressDispatcherTimer.IsEnabled = false;                                     
                    RaiseEvent(new RoutedEventArgs(LongPressReleaseEvent, this));
                    break;
            }
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            _clickDispatcherTimer = new DispatcherTimer();
            _clickDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
            _clickDispatcherTimer.Tick += ClickDispatcherTimeOut;
            _clickDispatcherTimer.IsEnabled = false;
            _pressDispatcherTimer = new DispatcherTimer();
            _pressDispatcherTimer.Tick += PressDispatcherTimeOut;
            _pressDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, LongPressTime);
            _pressDispatcherTimer.IsEnabled = false;
            _senderDispatcherTimer = new DispatcherTimer();
            _senderDispatcherTimer.Tick += SenderDispatcherTimeOut;
            _senderDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 100);
            _senderDispatcherTimer.IsEnabled = false;
        }

        private void button_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if(this.IsLoaded&&button.IsEnabled==false&& _clickState==ClickState.LONGPRESS_HOLDING)
            {
                StateChange(1);
            }                
        }
    }
}
